from django_redis import get_redis_connection

from apps.goods.models import GoodsCategory, \
    GoodsChannel, SKUSpecification


# 1. 首页和详情页获取分类和频道数据的函数
from utils.tools import tools


def get_categories():
    # 1. 查出频道数据(类别和频道组的关联表)
    goods_channels = GoodsChannel.objects.all().order_by('group', 'sequence')

    # 2. 把数据转换成前端想要的格式
    response_dict = {}
    for channel in goods_channels:
        # 0. 打印输出频道组的id  和频道关联到的类别名称
        # print(channel.group.id, channel.category.name)
        # 1. 得到频道组对应的商品类别
        category = channel.category

        # 2. 获取频道组大字典： 有就用已存在的，没有就构建一个
        group_dict = response_dict.get(channel.group.id)
        if not group_dict:
            group_dict = {'channels': [], 'sub_cats': []}
            response_dict[channel.group.id] = group_dict

        # 3. 往频道组的大字典中的channels中添加当前频道数据
        group_dict['channels'].append({"id": channel.id, "name": category.name, "url": channel.url})

        # 4. 得到一级类别下的所有二级类别
        sub_cats = category.subs.all()
        for sub_cat in sub_cats:
            # 4.1 准备二级类别字典
            sub_cat_dict = {'id': sub_cat.id, 'name': sub_cat.name, 'sub_cats': []}

            # 4.2 给二级字典类别字典的sub_cats添加三级类别的字典数据
            # 得到二级类别下的三级类别
            sub_thrid_cats = sub_cat.subs.all()
            for sub_thrid_cat in sub_thrid_cats:
                sub_cat_dict['sub_cats'].append({
                    'id': sub_thrid_cat.id,
                    'name': sub_thrid_cat.name}
                )
            # 4.3 把二级类别字典添加到组字典的 sub_cats列表中
            group_dict['sub_cats'].append(sub_cat_dict)
    return response_dict

# 2. 获取面包屑导航的函数
def get_breadcrumb(category_id):
    # 动态生成面包屑导航数据
    breadcrumb = {'cat1': '', 'cat2': '', 'cat3': ''}
    category = GoodsCategory.objects.get(id=category_id)

    # 如果没有父级，则当前类别是一级的类别
    if not category.parent:
        breadcrumb['cat1'] = category.name
    # 如果没有孩子（孩子的数量为0），则当前类别是三级类别
    elif category.subs.count() == 0:
        breadcrumb['cat1'] = category.parent.parent.name
        breadcrumb['cat2'] = category.parent.name
        breadcrumb['cat3'] = category.name
    # 剩下的情况就是二级类别
    else:
        breadcrumb['cat1'] = category.parent.name
        breadcrumb['cat2'] = category.name
    return breadcrumb

# 3. 获取规格数据的函数
def get_specs(sku):
    # 1. 构建字典: 通过选项反查sku_id的字典
    sku_specs = SKUSpecification.objects.filter(
        spec__spu=sku.spu).order_by('option')
    basic_dict = {}
    for sku_spec in sku_specs:
        sku_idl = str(sku_spec.sku.id)
        option_id = str(sku_spec.option.id)
        option_id_list = basic_dict.get(sku_idl)
        if not option_id_list:
            option_id_list = []
            basic_dict[sku_idl] = option_id_list
        option_id_list.append(option_id)

    find_sku_dict = {}
    for (key, value) in basic_dict.items():
        new_key = '_'.join(value)
        find_sku_dict[new_key] = key
    # print(find_sku_dict)

    # 2. 遍历处理数据
    specs = sku.spu.specs.all()
    for spec in specs:
        spec.spec_options = spec.options.all()
        for option in spec.spec_options:
            # option.sku_id = ?
            # 0. 已经拥有选项id:1
            option_id = option.id  # 1

            # 1. 找到当前选项1关联到的规格所有选项的id [1, 2]
            spec_options = option.spec.options.all()
            spec_option_ids = [str(spec_option.id) for spec_option in spec_options]

            # 2. 找到当前sku_id=3的sku关联到选项的id [2, 3]
            # 3. 找出在2中的数据，但是不在1中的数据   [3]
            sku_specs = sku.specs.all()
            # sku_option_ids = [str(sku_spec.option.id) for sku_spec in sku_specs]
            need_find_option_ids = []
            for sku_spec in sku_specs:
                sku_spec_option_id = str(sku_spec.option.id)
                if sku_spec_option_id not in spec_option_ids:
                    need_find_option_ids.append(str(sku_spec.option.id))

            # 3. 把已经拥有选项id:1  丢到3这个数组中 并进行增排序  [1, 3]
            need_find_option_ids.append(str(option_id))
            need_find_option_ids.sort()
            # print(need_find_option_ids)

            # 4. 利用[1, 3]拼出寻找sku_id的key  '1_3', 之后利用key去find_sku_dict去找出要找的sku_id
            find_sku_key = '_'.join(need_find_option_ids)
            sku_id = find_sku_dict.get(find_sku_key)
            if sku_id:
                option.sku_id = int(sku_id)
    return specs

# 4. 合并购物车的函数
def merge_cart_from_cookie_to_redis(request, user, response):
    # 6.1 查出cookie中购物车字符串数据
    carts_str = request.COOKIES.get('carts')
    # 6.2 如果没有字符串就不用做合并的处理
    # 6.3 如果有则合并
    if carts_str:
        # 1. 对字符串进行解密，得到购物车字典
        carts = tools.sloads(carts_str)

        # 2 把cookie中的数据转换成redis中的形式
        hash_dict = {}  # 放cookie中的商品数量
        add_sku_ids = []  # 放cookie中勾选的商品sku_id的列表
        remove_sku_ids = []  # 放cookie中需取消勾选的商品sku_id的列表
        # 2 把cookie中的数据转换成redis中的形式
        for (sku_id, cart_dict) in carts.items():
            hash_dict[sku_id] = cart_dict['count']
            if cart_dict['selected']:
                add_sku_ids.append(sku_id)
            else:
                remove_sku_ids.append(sku_id)
        # 3 修改redis中的数据
        conn = get_redis_connection('cart')
        pl = conn.pipeline()
        pl.hmset('carts_{}'.format(user.id), hash_dict)
        if add_sku_ids:
            pl.sadd('selected_{}'.format(user.id), *add_sku_ids)
        if remove_sku_ids:
            pl.srem('selected_{}'.format(user.id), *remove_sku_ids)
        pl.execute()
        # 4 扫尾：删除cookie中购物车数据
        response.delete_cookie('carts')
